!--------------------------------------------------------------------------------------------------!
!   CP2K: A general program to perform molecular dynamics simulations                              !
!   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
!                                                                                                  !
!   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
!--------------------------------------------------------------------------------------------------!

! **************************************************************************************************
!> \brief set up the different message for different tasks
!>      A TMC message consists of 3 parts (messages)
!>      1: first a message with task type (STATUS) and SIZES of submessages
!>      2: (if existing) a message with INTEGER values
!>      3: (if existing) a message with REAL values
!>      submessages 2 and 3 include relevant data, e.g. positions, box sizes...
!> \par History
!>      11.2012 created [Mandes Schoenherr]
!> \author Mandes
! **************************************************************************************************
MODULE tmc_messages
   USE cp_log_handling,                 ONLY: cp_to_string
   USE kinds,                           ONLY: default_string_length,&
                                              dp
   USE message_passing,                 ONLY: mp_any_source,&
                                              mp_any_tag,&
                                              mp_para_env_type
   USE tmc_move_handle,                 ONLY: add_mv_prob
   USE tmc_stati,                       ONLY: &
        TMC_CANCELING_MESSAGE, TMC_CANCELING_RECEIPT, TMC_STATUS_CALCULATING, TMC_STATUS_FAILED, &
        TMC_STATUS_STOP_RECEIPT, TMC_STATUS_WAIT_FOR_NEW_TASK, TMC_STATUS_WORKER_INIT, &
        TMC_STAT_ANALYSIS_REQUEST, TMC_STAT_ANALYSIS_RESULT, TMC_STAT_APPROX_ENERGY_REQUEST, &
        TMC_STAT_APPROX_ENERGY_RESULT, TMC_STAT_ENERGY_REQUEST, TMC_STAT_ENERGY_RESULT, &
        TMC_STAT_INIT_ANALYSIS, TMC_STAT_MD_BROADCAST, TMC_STAT_MD_REQUEST, TMC_STAT_MD_RESULT, &
        TMC_STAT_NMC_BROADCAST, TMC_STAT_NMC_REQUEST, TMC_STAT_NMC_RESULT, &
        TMC_STAT_SCF_STEP_ENER_RECEIVE, TMC_STAT_START_CONF_REQUEST, TMC_STAT_START_CONF_RESULT, &
        task_type_gaussian_adaptation
   USE tmc_tree_build,                  ONLY: allocate_new_sub_tree_node
   USE tmc_tree_types,                  ONLY: elem_array_type,&
                                              elem_list_type,&
                                              tree_type
   USE tmc_types,                       ONLY: allocate_tmc_atom_type,&
                                              tmc_atom_type,&
                                              tmc_param_type
#include "../base/base_uses.f90"

   IMPLICIT NONE

   PRIVATE

   LOGICAL, PARAMETER, PUBLIC                 :: send_msg = .TRUE.
   LOGICAL, PARAMETER, PUBLIC                 :: recv_msg = .FALSE.

   INTEGER, PARAMETER                         :: message_end_flag = 25

   INTEGER, PARAMETER                         :: DEBUG = 0

   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'tmc_messages'

   PUBLIC :: check_if_group_master
   PUBLIC :: tmc_message
   PUBLIC :: communicate_atom_types
   PUBLIC :: stop_whole_group

   INTEGER, PARAMETER, PUBLIC :: MASTER_COMM_ID = 0 ! id for master and group master
   INTEGER, PARAMETER, PUBLIC :: bcast_group = -1 ! destination flag for broadcasting to other group participants
   INTEGER, PARAMETER :: TMC_SEND_INFO_SIZE = 4 ! usually: 1. status, array sizes: 2. int, 3. real, 4. char

   TYPE message_send
      INTEGER, DIMENSION(TMC_SEND_INFO_SIZE)   :: info = -1
      REAL(KIND=dp), DIMENSION(:), ALLOCATABLE :: task_real
      INTEGER, DIMENSION(:), ALLOCATABLE       :: task_int
      CHARACTER, DIMENSION(:), ALLOCATABLE     :: task_char
      !should be deleted somewhen
      INTEGER, DIMENSION(:), ALLOCATABLE :: elem_stat
   END TYPE message_send

CONTAINS

! **************************************************************************************************
!> \brief checks if the core is the group master
!> \param para_env defines the mpi communicator
!> \return return value, logical
!> \author Mandes 01.2013
! **************************************************************************************************
   FUNCTION check_if_group_master(para_env) RESULT(master)
      TYPE(mp_para_env_type), POINTER                    :: para_env
      LOGICAL                                            :: master

      CPASSERT(ASSOCIATED(para_env))

      master = .FALSE.
      IF (para_env%mepos .EQ. MASTER_COMM_ID) &
         master = .TRUE.
   END FUNCTION check_if_group_master

! **************************************************************************************************
!> \brief tmc message handling, packing messages with integer and real data
!>        type. Send first info message with task type and message sizes and
!>        then the int and real messages. The same for receiving
!> \param msg_type defines the message types, see message tags definition
!> \param send_recv 1= send, 0= receive
!> \param dest defines the target or source of message
!>              (-1=braodcast, 0= master, 1... working group)
!> \param para_env defines the mpi communicator
!> \param tmc_params stuct with parameters (global settings)
!> \param elem a subtree element from which info are readed or written in
!> \param elem_array ...
!> \param list_elem ...
!> \param result_count ...
!> \param wait_for_message ...
!> \param success ...
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE tmc_message(msg_type, send_recv, dest, para_env, tmc_params, &
                          elem, elem_array, list_elem, result_count, &
                          wait_for_message, success)
      INTEGER                                            :: msg_type
      LOGICAL                                            :: send_recv
      INTEGER                                            :: dest
      TYPE(mp_para_env_type), POINTER                    :: para_env
      TYPE(tmc_param_type), POINTER                      :: tmc_params
      TYPE(tree_type), OPTIONAL, POINTER                 :: elem
      TYPE(elem_array_type), DIMENSION(:), OPTIONAL      :: elem_array
      TYPE(elem_list_type), OPTIONAL, POINTER            :: list_elem
      INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: result_count
      LOGICAL, OPTIONAL                                  :: wait_for_message, success

      INTEGER                                            :: i, message_tag, tmp_tag
      LOGICAL                                            :: act_send_recv, flag
      TYPE(message_send), POINTER                        :: m_send

      CPASSERT(ASSOCIATED(para_env))
      CPASSERT(ASSOCIATED(tmc_params))

      ALLOCATE (m_send)

      ! init
      ! define send_recv flag for broadcast
      IF (dest .EQ. bcast_group) THEN
         ! master should always send
         IF (para_env%mepos .EQ. MASTER_COMM_ID) THEN
            act_send_recv = send_msg
         ELSE
            ! worker should always receive
            act_send_recv = recv_msg
         END IF
      ELSE
         act_send_recv = send_recv
      END IF
      message_tag = 0

      ! =============================
      ! sending message
      ! =============================
      ! creating message to send
      IF (act_send_recv .EQV. send_msg) THEN
         IF ((DEBUG .GE. 7) .AND. (dest .NE. bcast_group) .AND. &
             (dest .NE. MASTER_COMM_ID)) THEN
            IF (PRESENT(elem)) THEN
               WRITE (*, *) "send element info to ", dest, " of type ", msg_type, "of subtree", elem%sub_tree_nr, &
                  "elem", elem%nr
            ELSE
               WRITE (*, *) "send element info to ", dest, " of type ", msg_type
            END IF
         END IF
         SELECT CASE (msg_type)
         CASE (TMC_STAT_START_CONF_REQUEST, TMC_STATUS_FAILED, TMC_CANCELING_MESSAGE, &
               TMC_CANCELING_RECEIPT, TMC_STATUS_STOP_RECEIPT, &
               TMC_STATUS_WAIT_FOR_NEW_TASK, TMC_STATUS_CALCULATING, &
               TMC_STAT_ANALYSIS_RESULT)
            CALL create_status_message(m_send)
         CASE (TMC_STATUS_WORKER_INIT)
            CALL create_worker_init_message(tmc_params, m_send)
         CASE (TMC_STAT_START_CONF_RESULT, TMC_STAT_INIT_ANALYSIS)
            CALL create_start_conf_message(msg_type, elem, result_count, tmc_params, m_send)
         CASE (TMC_STAT_ENERGY_REQUEST, TMC_STAT_APPROX_ENERGY_REQUEST)
            CALL create_energy_request_message(elem, m_send, tmc_params)
         CASE (TMC_STAT_APPROX_ENERGY_RESULT)
            CALL create_approx_energy_result_message(elem, m_send, tmc_params)
         CASE (TMC_STAT_ENERGY_RESULT)
            CALL create_energy_result_message(elem, m_send, tmc_params)
         CASE (TMC_STAT_NMC_REQUEST, TMC_STAT_NMC_BROADCAST, &
               TMC_STAT_MD_REQUEST, TMC_STAT_MD_BROADCAST)
            CALL create_NMC_request_massage(msg_type, elem, m_send, tmc_params)
         CASE (TMC_STAT_MD_RESULT, TMC_STAT_NMC_RESULT)
            CALL create_NMC_result_massage(msg_type, elem, m_send, tmc_params)
         CASE (TMC_STAT_ANALYSIS_REQUEST)
            CPASSERT(PRESENT(list_elem))
            CALL create_analysis_request_message(list_elem, m_send, tmc_params)
         CASE DEFAULT
            CPABORT("try to send unknown message type "//cp_to_string(msg_type))
         END SELECT
         !set message info
         message_tag = msg_type
         m_send%info(:) = 0
         m_send%info(1) = msg_type
         IF (ALLOCATED(m_send%task_int)) m_send%info(2) = SIZE(m_send%task_int)
         IF (ALLOCATED(m_send%task_real)) m_send%info(3) = SIZE(m_send%task_real)
         IF (ALLOCATED(m_send%task_char)) m_send%info(4) = SIZE(m_send%task_char)
      END IF

      ! sending message
      IF ((act_send_recv .EQV. send_msg) .AND. (dest .NE. bcast_group)) THEN
         CALL para_env%send(m_send%info, dest, message_tag)
         IF (m_send%info(2) .GT. 0) THEN
            CALL para_env%send(m_send%task_int, dest, message_tag)
         END IF
         IF (m_send%info(3) .GT. 0) THEN
            CALL para_env%send(m_send%task_real, dest, message_tag)
         END IF
         IF (m_send%info(4) .GT. 0) THEN
            CPABORT("")
            !TODO send characters CALL para_env%send(m_send%task_char, dest, message_tag)
         END IF
         IF (DEBUG .GE. 1) &
            WRITE (*, *) "TMC|message: ID: ", para_env%mepos, &
            " send element info to   ", dest, " of stat ", m_send%info(1), &
            " with size int/real/char", m_send%info(2:), " with comm ", &
            para_env%get_handle(), " and tag ", message_tag
         IF (m_send%info(2) .GT. 0) DEALLOCATE (m_send%task_int)
         IF (m_send%info(3) .GT. 0) DEALLOCATE (m_send%task_real)
         IF (m_send%info(4) .GT. 0) DEALLOCATE (m_send%task_char)
         IF (PRESENT(success)) success = .TRUE.
      END IF

      ! =============================
      ! broadcast
      ! =============================
      IF (dest .EQ. bcast_group) THEN
         IF (para_env%num_pe .GT. 1) THEN
            CALL para_env%bcast(m_send%info, MASTER_COMM_ID)
            IF (m_send%info(2) .GT. 0) THEN
               IF (.NOT. act_send_recv) ALLOCATE (m_send%task_int(m_send%info(2)))
               CALL para_env%bcast(m_send%task_int, MASTER_COMM_ID)
            END IF
            IF (m_send%info(3) .GT. 0) THEN
               IF (.NOT. act_send_recv) ALLOCATE (m_send%task_real(m_send%info(3)))
               CALL para_env%bcast(m_send%task_real, MASTER_COMM_ID)
            END IF
            IF (m_send%info(4) .GT. 0) THEN
               IF (.NOT. act_send_recv) ALLOCATE (m_send%task_char(m_send%info(3)))
               CPABORT("")
               !TODO bcast char CALL para_env%bcast(m_send%task_char, MASTER_COMM_ID)
            END IF
         END IF
         ! sender delete arrays
         IF (act_send_recv) THEN
            IF (m_send%info(2) .GT. 0) DEALLOCATE (m_send%task_int)
            IF (m_send%info(3) .GT. 0) DEALLOCATE (m_send%task_real)
            IF (m_send%info(4) .GT. 0) DEALLOCATE (m_send%task_char)
         END IF
      END IF

      ! =============================
      ! receiving message
      ! =============================
      IF ((act_send_recv .EQV. recv_msg) .AND. dest .NE. bcast_group) THEN
         flag = .FALSE.
         tmp_tag = TMC_STATUS_WAIT_FOR_NEW_TASK
         IF (PRESENT(wait_for_message)) THEN
            dest = mp_any_source
            CALL para_env%probe(dest, tmp_tag)
            flag = .TRUE.
         ELSE
            participant_loop: DO i = 0, para_env%num_pe - 1
               IF (i .NE. para_env%mepos) THEN
                  dest = i
                  CALL para_env%probe(dest, tmp_tag)
                  IF (dest .EQ. i) THEN
                     flag = .TRUE.
                     EXIT participant_loop
                  END IF
               END IF
            END DO participant_loop
         END IF
         IF (flag .EQV. .FALSE.) THEN
            IF (PRESENT(success)) success = .FALSE.
            DEALLOCATE (m_send)
            RETURN
         END IF

         IF (tmp_tag .EQ. TMC_STAT_SCF_STEP_ENER_RECEIVE) THEN
            ! CP2K send back SCF step energies without info message
            message_tag = TMC_STAT_SCF_STEP_ENER_RECEIVE
            m_send%info(1) = TMC_STAT_SCF_STEP_ENER_RECEIVE
            m_send%info(2) = 0 ! no integer values
            m_send%info(3) = 1 ! one double values (SCF total energy)
            m_send%info(4) = 0 ! no character values
         ELSE
            message_tag = mp_any_tag
            ! first get message type and sizes
            CALL para_env%recv(m_send%info, dest, message_tag)
         END IF
         IF (DEBUG .GE. 1) &
            WRITE (*, *) "TMC|message: ID: ", para_env%mepos, &
            " recv element info from ", dest, " of stat ", m_send%info(1), &
            " with size int/real/char", m_send%info(2:)
         !-- receive message integer part
         IF (m_send%info(2) .GT. 0) THEN
            ALLOCATE (m_send%task_int(m_send%info(2)))
            CALL para_env%recv(m_send%task_int, dest, message_tag)
         END IF
         !-- receive message double (floatingpoint) part
         IF (m_send%info(3) .GT. 0) THEN
            ALLOCATE (m_send%task_real(m_send%info(3)))
            CALL para_env%recv(m_send%task_real, dest, message_tag)
         END IF
         !-- receive message character part
         IF (m_send%info(4) .GT. 0) THEN
            ALLOCATE (m_send%task_char(m_send%info(4)))
            CPABORT("")
            !TODO recv characters CALL para_env%recv(m_send%task_char, dest, message_tag)
         END IF
      END IF

      ! handling received message
      IF (act_send_recv .EQV. recv_msg) THEN
         ! if the element is supposed to be canceled but received message is not canceling receipt do not handle element
         ! (because element could be already deallocated, and hence a new element would be created -> not necessary)
         IF (PRESENT(elem_array)) THEN
            IF (elem_array(dest)%canceled .AND. m_send%info(1) .NE. TMC_CANCELING_RECEIPT) THEN
               msg_type = m_send%info(1)
               IF (m_send%info(2) .GT. 0) DEALLOCATE (m_send%task_int)
               IF (m_send%info(3) .GT. 0) DEALLOCATE (m_send%task_real)
               IF (m_send%info(4) .GT. 0) DEALLOCATE (m_send%task_char)
               ! to check for further messages
               IF (PRESENT(success)) success = .TRUE.
               DEALLOCATE (m_send)
               RETURN
            END IF
         END IF

         msg_type = m_send%info(1)
         SELECT CASE (m_send%info(1))
         CASE (TMC_STAT_START_CONF_REQUEST, TMC_CANCELING_MESSAGE, &
               TMC_CANCELING_RECEIPT, TMC_STATUS_WAIT_FOR_NEW_TASK, &
               TMC_STATUS_CALCULATING, TMC_STAT_ANALYSIS_RESULT)
            ! nothing to do here
         CASE (TMC_STATUS_WORKER_INIT)
            CALL read_worker_init_message(tmc_params, m_send)
         CASE (TMC_STAT_START_CONF_RESULT, TMC_STAT_INIT_ANALYSIS)
            IF (PRESENT(elem_array)) THEN
               CALL read_start_conf_message(msg_type, elem_array(dest)%elem, &
                                            result_count, m_send, tmc_params)
            ELSE
               CALL read_start_conf_message(msg_type, elem, result_count, m_send, &
                                            tmc_params)
            END IF
         CASE (TMC_STAT_APPROX_ENERGY_RESULT)
            CALL read_approx_energy_result(elem_array(dest)%elem, m_send, tmc_params)
         CASE (TMC_STAT_ENERGY_REQUEST, TMC_STAT_APPROX_ENERGY_REQUEST)
            CALL read_energy_request_message(elem, m_send, tmc_params)
         CASE (TMC_STAT_ENERGY_RESULT)
            IF (PRESENT(elem_array)) &
               CALL read_energy_result_message(elem_array(dest)%elem, m_send, tmc_params)
         CASE (TMC_STAT_NMC_REQUEST, TMC_STAT_NMC_BROADCAST, &
               TMC_STAT_MD_REQUEST, TMC_STAT_MD_BROADCAST)
            CALL read_NMC_request_massage(msg_type, elem, m_send, tmc_params)
         CASE (TMC_STAT_NMC_RESULT, TMC_STAT_MD_RESULT)
            IF (PRESENT(elem_array)) &
               CALL read_NMC_result_massage(msg_type, elem_array(dest)%elem, m_send, tmc_params)
         CASE (TMC_STATUS_FAILED, TMC_STATUS_STOP_RECEIPT)
            ! if task is failed, handle situation in outer routine
         CASE (TMC_STAT_SCF_STEP_ENER_RECEIVE)
            CALL read_scf_step_ener(elem_array(dest)%elem, m_send)
         CASE (TMC_STAT_ANALYSIS_REQUEST)
            CALL read_analysis_request_message(elem, m_send, tmc_params)
         CASE DEFAULT
            CALL cp_abort(__LOCATION__, &
                          "try to receive unknown message type "//cp_to_string(msg_type)// &
                          "from source "//cp_to_string(dest))
         END SELECT
         IF (m_send%info(2) .GT. 0) DEALLOCATE (m_send%task_int)
         IF (m_send%info(3) .GT. 0) DEALLOCATE (m_send%task_real)
         IF (m_send%info(4) .GT. 0) DEALLOCATE (m_send%task_char)
         IF (PRESENT(success)) success = .TRUE.
      END IF

      ! ATTENTION there is also an short exit (RETURN) after probing for new messages
      DEALLOCATE (m_send)
   END SUBROUTINE tmc_message

! **************************************************************************************************
!> \brief set the messege just with an status tag
!> \param m_send the message structure
!> \author Mandes 12.2012
! **************************************************************************************************

   SUBROUTINE create_status_message(m_send)
      TYPE(message_send), POINTER                        :: m_send

      CPASSERT(ASSOCIATED(m_send))

      ! nothing to do, send just the message tag

      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      MARK_USED(m_send)

   END SUBROUTINE create_status_message

   !============================================================================
   ! message for requesting start configuration
   !============================================================================
!! **************************************************************************************************
!!> \brief the message for sending the atom mass
!!>        (number of atoms is also tranfered)
!!>        atom names have to be done separately,
!!>        because character send only with bcast possible
!!> \param tmc_parms th send the cell properties
!!> \param m_send the message structure
!!> \param error variable to control error logging, stopping,...
!!>        see module cp_error_handling
!!> \author Mandes 02.2013
!! **************************************************************************************************
!  SUBROUTINE create_atom_mass_message(m_send, atoms)
!    TYPE(tmc_atom_type), DIMENSION(:), POINTER    :: atoms
!    TYPE(message_send), POINTER              :: m_send
!
!    CHARACTER(LEN=*), PARAMETER :: routineN = 'create_atom_mass_message', &
!      routineP = moduleN//':'//routineN
!
!    INTEGER                                  :: counter, i, &
!                                                msg_size_real
!    LOGICAL                                  :: failure
!
!    failure = .FALSE.
!
!    CPPrecondition(ASSOCIATED(m_send),cp_failure_level,routineP,failure)
!    CPPrecondition(.NOT.ALLOCATED(m_send%task_int),cp_failure_level,routineP,failure)
!    CPPrecondition(.NOT.ALLOCATED(m_send%task_real),cp_failure_level,routineP,failure)
!    CPPrecondition(.NOT.ALLOCATED(m_send%task_char),cp_failure_level,routineP,failure)
!
!    counter =1
!    msg_size_real = 1+SIZE(tmc_params%cell%hmat)+ 1+SIZE(atoms) +1
!    ALLOCATE(m_send%task_real(msg_size_real))
!
!    m_send%task_real(1) = REAL(SIZE(atoms,KIND=dp))
!    DO i=1, SIZE(atoms)
!      m_send%task_real(counter+i) = atoms(i)%mass
!    END DO
!    counter = counter + 1+INT(m_send%task_real(counter))
!    m_send%task_real(counter) = REAL(message_end_flag, KIND=dp) !message end
!    CPPostconditionNoFail(INT(m_send%task_real(msg_size_real)).EQ.message_end_flag,cp_failure_level,routineP)
!  END SUBROUTINE create_atom_mass_message
!
!! **************************************************************************************************
!!> \brief the message for reading the atom mass
!!>        (number of atoms is also tranfered)
!!>        atom names have to be done separately,
!!>        because character send only with bcast possible
!!> \param tmc_parms th send the cell properties
!!> \param m_send the message structure
!!> \param error variable to control error logging, stopping,...
!!>        see module cp_error_handling
!!> \author Mandes 02.2013
!! **************************************************************************************************
!  SUBROUTINE read_atom_mass_message(m_send, atoms)
!    TYPE(tmc_atom_type), DIMENSION(:), &
!      POINTER                                :: atoms
!    TYPE(message_send), POINTER              :: m_send
!
!    CHARACTER(LEN=*), PARAMETER :: routineN = 'read_atom_mass_message', &
!      routineP = moduleN//':'//routineN
!
!    INTEGER                                  :: counter, i, nr_atoms
!    LOGICAL                                  :: failure
!
!    failure = .FALSE.
!
!    CPPrecondition(ASSOCIATED(m_send),cp_failure_level,routineP,failure)
!    CPPrecondition(.NOT.ALLOCATED(m_send%task_int),cp_failure_level,routineP,failure)
!    CPPrecondition(ALLOCATED(m_send%task_real),cp_failure_level,routineP,failure)
!    CPPrecondition(.NOT.ALLOCATED(m_send%task_char),cp_failure_level,routineP,failure)
!
!    counter =1
!    nr_atoms = m_send%task_real(counter)
!    IF(.NOT.ASSOCIATED(atoms)) CALL allocate_tmc_atom_type(atoms, nr_atoms)
!    DO i=1, SIZE(atoms)
!      atoms(i)%mass = m_send%task_real(counter+i)
!    END DO
!    counter = counter + 1+INT(m_send%task_real(counter))
!    CPPostconditionNoFail(INT(m_send%task_real(counter)).EQ.message_end_flag,cp_failure_level,routineP)
!  END SUBROUTINE read_atom_mass_message

! **************************************************************************************************
!> \brief the message for the initial values (cell size) to the workers
!> \param tmc_params to send the cell properties
!> \param m_send the message structure
!> \author Mandes 07.2013
! **************************************************************************************************
   SUBROUTINE create_worker_init_message(tmc_params, m_send)
      TYPE(tmc_param_type), POINTER                      :: tmc_params
      TYPE(message_send), POINTER                        :: m_send

      INTEGER                                            :: counter, msg_size_int, msg_size_real

      CPASSERT(ASSOCIATED(tmc_params))
      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(.NOT. ALLOCATED(m_send%task_char))
      CPASSERT(ASSOCIATED(tmc_params%cell))

      counter = 1
      msg_size_int = 1 + SIZE(tmc_params%cell%perd) + 1 + 1 + 1 + 1
      ALLOCATE (m_send%task_int(msg_size_int))
      m_send%task_int(counter) = SIZE(tmc_params%cell%perd) ! periodicity of the cell
      counter = counter + 1 + m_send%task_int(counter)
      m_send%task_int(2:counter - 1) = tmc_params%cell%perd(:)
      m_send%task_int(counter) = 1
      m_send%task_int(counter + 1) = tmc_params%cell%symmetry_id
      m_send%task_int(counter + 2) = 0
      IF (tmc_params%cell%orthorhombic) m_send%task_int(counter + 2) = 1
      counter = counter + 3
      m_send%task_int(counter) = message_end_flag
      CPASSERT(counter .EQ. SIZE(m_send%task_int))

      !float array with cell vectors
      msg_size_real = 1 + SIZE(tmc_params%cell%hmat) + 1
      ALLOCATE (m_send%task_real(msg_size_real))
      counter = 1
      m_send%task_real(counter) = SIZE(tmc_params%cell%hmat) ! cell vectors for cell size
      m_send%task_real(counter + 1:counter + SIZE(tmc_params%cell%hmat)) = &
         RESHAPE(tmc_params%cell%hmat(:, :), &
                 (/SIZE(tmc_params%cell%hmat)/))
      counter = counter + 1 + INT(m_send%task_real(counter))
      m_send%task_real(counter) = REAL(message_end_flag, KIND=dp) !message end
      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)
   END SUBROUTINE create_worker_init_message

! **************************************************************************************************
!> \brief the message for the initial values (cell size) to the workers
!> \param tmc_params to send the cell properties
!> \param m_send the message structure
!> \author Mandes 07.2013
! **************************************************************************************************
   SUBROUTINE read_worker_init_message(tmc_params, m_send)
      TYPE(tmc_param_type), POINTER                      :: tmc_params
      TYPE(message_send), POINTER                        :: m_send

      INTEGER                                            :: counter
      LOGICAL                                            :: flag

      CPASSERT(ASSOCIATED(tmc_params))
      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(m_send%info(3) .GE. 4)

      IF (.NOT. ASSOCIATED(tmc_params%cell)) ALLOCATE (tmc_params%cell)
      counter = 1
      !int array
      flag = INT(m_send%task_int(1)) .EQ. SIZE(tmc_params%cell%perd)
      CPASSERT(flag)
      counter = 1 + m_send%task_int(1) + 1
      tmc_params%cell%perd = m_send%task_int(2:counter - 1)
      tmc_params%cell%symmetry_id = m_send%task_int(counter + 1)
      tmc_params%cell%orthorhombic = .FALSE.
      IF (m_send%task_int(counter + 2) .EQ. 1) tmc_params%cell%orthorhombic = .TRUE.
      counter = counter + 3
      CPASSERT(counter .EQ. m_send%info(2))
      CPASSERT(m_send%task_int(counter) .EQ. message_end_flag)

      !float array with cell vectors
      counter = 1
      flag = INT(m_send%task_real(counter)) .EQ. SIZE(tmc_params%cell%hmat)
      CPASSERT(flag)
      tmc_params%cell%hmat = &
         RESHAPE(m_send%task_real(counter + 1:counter + &
                                  SIZE(tmc_params%cell%hmat)), (/3, 3/))
      counter = counter + 1 + INT(m_send%task_real(counter))

      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)

   END SUBROUTINE read_worker_init_message

! **************************************************************************************************
!> \brief the message for sending back the initial configuration
!> \param msg_type the status tag
!> \param elem the initial tree element with initial coordinates and energy
!>        (using the approximated potential)
!> \param result_count ...
!> \param tmc_params to send the cell properties
!> \param m_send the message structure
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE create_start_conf_message(msg_type, elem, result_count, &
                                        tmc_params, m_send)
      INTEGER                                            :: msg_type
      TYPE(tree_type), POINTER                           :: elem
      INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: result_count
      TYPE(tmc_param_type), POINTER                      :: tmc_params
      TYPE(message_send), POINTER                        :: m_send

      INTEGER                                            :: counter, i, msg_size_int, msg_size_real

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(tmc_params))
      CPASSERT(ASSOCIATED(tmc_params%atoms))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(.NOT. ALLOCATED(m_send%task_char))

      counter = 1
      msg_size_int = 1 + SIZE(tmc_params%cell%perd) + 1 + 1 + 1 + 1 + SIZE(elem%mol) + 1
      IF (msg_type .EQ. TMC_STAT_INIT_ANALYSIS) THEN
         CPASSERT(PRESENT(result_count))
         CPASSERT(ASSOCIATED(result_count))
         msg_size_int = msg_size_int + 1 + SIZE(result_count(1:))
      END IF
      ALLOCATE (m_send%task_int(msg_size_int))
      m_send%task_int(counter) = SIZE(tmc_params%cell%perd) ! periodicity of the cell
      counter = counter + 1 + m_send%task_int(counter)
      m_send%task_int(2:counter - 1) = tmc_params%cell%perd(:)
      m_send%task_int(counter) = 1
      m_send%task_int(counter + 1) = tmc_params%cell%symmetry_id
      m_send%task_int(counter + 2) = 0
      IF (tmc_params%cell%orthorhombic) m_send%task_int(counter + 2) = 1
      counter = counter + 3
      m_send%task_int(counter) = SIZE(elem%mol)
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = elem%mol(:)
      counter = counter + 1 + m_send%task_int(counter)
      IF (msg_type .EQ. TMC_STAT_INIT_ANALYSIS) THEN
         m_send%task_int(counter) = SIZE(result_count(1:))
         m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = &
            result_count(1:)
         counter = counter + 1 + m_send%task_int(counter)
      END IF
      m_send%task_int(counter) = message_end_flag
      CPASSERT(counter .EQ. SIZE(m_send%task_int))

      counter = 0
      !float array with pos, cell vectors, atom_mass
      msg_size_real = 1 + SIZE(elem%pos) + 1 + SIZE(tmc_params%cell%hmat) &
                      + 1 + SIZE(tmc_params%atoms) + 1
      ALLOCATE (m_send%task_real(msg_size_real))
      m_send%task_real(1) = REAL(SIZE(elem%pos), KIND=dp) ! positions
      counter = 2 + INT(m_send%task_real(1))
      m_send%task_real(2:counter - 1) = elem%pos
      m_send%task_real(counter) = SIZE(tmc_params%cell%hmat) ! cell vectors for cell size
      m_send%task_real(counter + 1:counter + SIZE(tmc_params%cell%hmat)) = &
         RESHAPE(tmc_params%cell%hmat(:, :), &
                 (/SIZE(tmc_params%cell%hmat)/))
      counter = counter + 1 + INT(m_send%task_real(counter))
      m_send%task_real(counter) = SIZE(tmc_params%atoms) ! atom mass
      DO i = 1, SIZE(tmc_params%atoms)
         m_send%task_real(counter + i) = tmc_params%atoms(i)%mass
      END DO
      counter = counter + 1 + INT(m_send%task_real(counter))
      m_send%task_real(counter) = REAL(message_end_flag, KIND=dp) !message end
      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)

   END SUBROUTINE create_start_conf_message

! **************************************************************************************************
!> \brief the message for sending back the initial configuration
!> \param msg_type the status tag
!> \param elem the initial tree element with initial coordinates and energy
!>        (using the approximated potential)
!> \param result_count ...
!> \param m_send the message structure
!> \param tmc_params the param struct with necessary values for allocation
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_start_conf_message(msg_type, elem, result_count, m_send, &
                                      tmc_params)
      INTEGER                                            :: msg_type
      TYPE(tree_type), POINTER                           :: elem
      INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: result_count
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, i
      LOGICAL                                            :: flag

      CPASSERT(ASSOCIATED(tmc_params))
      CPASSERT(.NOT. ASSOCIATED(tmc_params%atoms))
      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(.NOT. ASSOCIATED(elem))
      CPASSERT(m_send%info(3) .GE. 4)

      IF (.NOT. ASSOCIATED(tmc_params%cell)) ALLOCATE (tmc_params%cell)
      CALL allocate_new_sub_tree_node(tmc_params=tmc_params, next_el=elem, &
                                      nr_dim=NINT(m_send%task_real(1)))
      counter = 1
      !int array
      flag = INT(m_send%task_int(1)) .EQ. SIZE(tmc_params%cell%perd)
      CPASSERT(flag)
      counter = 1 + m_send%task_int(1) + 1
      tmc_params%cell%perd = m_send%task_int(2:counter - 1)
      tmc_params%cell%symmetry_id = m_send%task_int(counter + 1)
      tmc_params%cell%orthorhombic = .FALSE.
      IF (m_send%task_int(counter + 2) .EQ. 1) tmc_params%cell%orthorhombic = .TRUE.
      counter = counter + 3
      elem%mol(:) = m_send%task_int(counter + 1:counter + m_send%task_int(counter))
      counter = counter + 1 + m_send%task_int(counter)
      IF (msg_type .EQ. TMC_STAT_INIT_ANALYSIS) THEN
         CPASSERT(PRESENT(result_count))
         CPASSERT(.NOT. ASSOCIATED(result_count))
         ALLOCATE (result_count(m_send%task_int(counter)))
         result_count(:) = m_send%task_int(counter + 1:counter + m_send%task_int(counter))
         counter = counter + 1 + m_send%task_int(counter)
      END IF
      CPASSERT(counter .EQ. m_send%info(2))
      CPASSERT(m_send%task_int(counter) .EQ. message_end_flag)

      counter = 0
      !float array with pos, cell vectors, atom_mass
      counter = 2 + INT(m_send%task_real(1))
      elem%pos = m_send%task_real(2:counter - 1)
      flag = INT(m_send%task_real(counter)) .EQ. SIZE(tmc_params%cell%hmat)
      CPASSERT(flag)
      tmc_params%cell%hmat = &
         RESHAPE(m_send%task_real(counter + 1:counter + &
                                  SIZE(tmc_params%cell%hmat)), (/3, 3/))
      counter = counter + 1 + INT(m_send%task_real(counter))

      CALL allocate_tmc_atom_type(atoms=tmc_params%atoms, &
                                  nr_atoms=INT(m_send%task_real(counter)))
      DO i = 1, SIZE(tmc_params%atoms)
         tmc_params%atoms(i)%mass = m_send%task_real(counter + i)
      END DO
      counter = counter + 1 + INT(m_send%task_real(counter))

      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)

   END SUBROUTINE read_start_conf_message

   !============================================================================
   ! Energy messages
   !============================================================================
! **************************************************************************************************
!> \brief creating message for requesting exact energy of new configuration
!> \param elem tree element with new coordinates
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE create_energy_request_message(elem, m_send, &
                                            tmc_params)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, msg_size_int, msg_size_real

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(tmc_params))

      counter = 0
      !first integer array
      msg_size_int = 1 + 1 + 1 + 1 + 1 ! 1+SIZE(elem%sub_tree_nr) +1+SIZE(elem%nr)
      ALLOCATE (m_send%task_int(msg_size_int))
      counter = 1
      m_send%task_int(counter) = 1 !SIZE(elem%sub_tree_nr)
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = elem%sub_tree_nr
      counter = counter + 1 + m_send%task_int(counter)
      m_send%task_int(counter) = 1 !SIZE(elem%nr)
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = elem%nr
      counter = counter + 1 + m_send%task_int(counter)
      m_send%task_int(counter) = message_end_flag
      CPASSERT(SIZE(m_send%task_int) .EQ. msg_size_int)
      CPASSERT(m_send%task_int(msg_size_int) .EQ. message_end_flag)

      !then float array with pos
      msg_size_real = 1 + SIZE(elem%pos) + 1
      IF (tmc_params%pressure .GE. 0.0_dp) msg_size_real = msg_size_real + 1 + SIZE(elem%box_scale(:))
      ALLOCATE (m_send%task_real(msg_size_real))
      m_send%task_real(1) = SIZE(elem%pos)
      counter = 2 + INT(m_send%task_real(1))
      m_send%task_real(2:counter - 1) = elem%pos
      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         m_send%task_real(counter) = SIZE(elem%box_scale)
         m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter))) = elem%box_scale(:)
         counter = counter + 1 + INT(m_send%task_real(counter))
      END IF
      m_send%task_real(counter) = REAL(message_end_flag, KIND=dp) !message end

      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)
   END SUBROUTINE create_energy_request_message

! **************************************************************************************************
!> \brief reading message for requesting exact energy of new configuration
!> \param elem tree element with new coordinates
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_energy_request_message(elem, m_send, tmc_params)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(m_send%info(3) .GT. 0)
      CPASSERT(ASSOCIATED(tmc_params))
      CPASSERT(.NOT. ASSOCIATED(elem))

      ! initialize the new sub tree element
      IF (.NOT. ASSOCIATED(elem)) THEN
         CALL allocate_new_sub_tree_node(next_el=elem, nr_dim=NINT(m_send%task_real(1)), &
                                         tmc_params=tmc_params)
      END IF
      ! read the integer values
      CPASSERT(m_send%info(2) .GT. 0)
      counter = 1
      elem%sub_tree_nr = m_send%task_int(counter + 1)
      counter = counter + 1 + m_send%task_int(counter)
      elem%nr = m_send%task_int(counter + 1)
      counter = counter + 1 + m_send%task_int(counter)
      CPASSERT(m_send%task_int(counter) .EQ. message_end_flag)

      !float array with pos
      counter = 0
      counter = 1 + NINT(m_send%task_real(1))
      elem%pos = m_send%task_real(2:counter)
      counter = counter + 1
      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         elem%box_scale(:) = m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter)))
         counter = counter + 1 + INT(m_send%task_real(counter))
      END IF

      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)
   END SUBROUTINE read_energy_request_message

! **************************************************************************************************
!> \brief creating message for sending back the exact energy of new conf
!> \param elem tree element  with calculated energy
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE create_energy_result_message(elem, m_send, tmc_params)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, msg_size_int, msg_size_real

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(tmc_params))

      counter = 0
      !first integer array
      msg_size_int = 0
      ! for checking the tree element mapping, send back the tree numbers
      IF (DEBUG .GT. 0) THEN
         msg_size_int = 1 + 1 + 1 + 1 + 1 ! 1+SIZE(elem%sub_tree_nr) +1+SIZE(elem%nr)
         ALLOCATE (m_send%task_int(msg_size_int))
         counter = 1
         m_send%task_int(counter) = 1 !SIZE(elem%sub_tree_nr)
         m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = elem%sub_tree_nr
         counter = counter + 1 + m_send%task_int(counter)
         m_send%task_int(counter) = 1 !SIZE(elem%nr)
         m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = elem%nr
         counter = counter + m_send%task_int(counter) + 1
         m_send%task_int(counter) = message_end_flag !message end
      END IF

      !then float array with energy of exact potential
      msg_size_real = 1 + 1 + 1
      IF (tmc_params%print_forces) msg_size_real = msg_size_real + 1 + SIZE(elem%frc)
      IF (tmc_params%print_dipole) msg_size_real = msg_size_real + 1 + SIZE(elem%dipole)

      ALLOCATE (m_send%task_real(msg_size_real))
      m_send%task_real(1) = 1
      m_send%task_real(2) = elem%potential
      counter = 3
      IF (tmc_params%print_forces) THEN
         m_send%task_real(counter) = SIZE(elem%frc)
         m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter))) = elem%frc
         counter = counter + NINT(m_send%task_real(counter)) + 1
      END IF
      IF (tmc_params%print_dipole) THEN
         m_send%task_real(counter) = SIZE(elem%dipole)
         m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter))) = elem%dipole
         counter = counter + NINT(m_send%task_real(counter)) + 1
      END IF

      m_send%task_real(counter) = REAL(message_end_flag, KIND=dp) !message end

      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)
   END SUBROUTINE create_energy_result_message

! **************************************************************************************************
!> \brief reading message for sending back the exact energy of new conf
!> \param elem tree element for storing new energy
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_energy_result_message(elem, m_send, tmc_params)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter

      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(m_send%info(3) .GT. 0)
      CPASSERT(ASSOCIATED(tmc_params))

      ! read the integer values
      ! for checking the tree element mapping, check the tree numbers
      IF (DEBUG .GT. 0) THEN
         counter = 1
         IF (elem%sub_tree_nr .NE. m_send%task_int(counter + 1) .OR. &
             elem%nr .NE. m_send%task_int(counter + 3)) THEN
            WRITE (*, *) "ERROR: read_energy_result: master got energy result of subtree elem ", &
               m_send%task_int(counter + 1), m_send%task_int(counter + 3), &
               " but expect result of subtree elem", elem%sub_tree_nr, elem%nr
            CPABORT("read_energy_result: got energy result from unexpected tree element.")
         END IF
      ELSE
         CPASSERT(m_send%info(2) .EQ. 0)
      END IF

      !then float array with energy of exact potential
      elem%potential = m_send%task_real(2)
      counter = 3
      IF (tmc_params%print_forces) THEN
         elem%frc(:) = m_send%task_real((counter + 1):(counter + NINT(m_send%task_real(counter))))
         counter = counter + 1 + NINT(m_send%task_real(counter))
      END IF
      IF (tmc_params%print_dipole) THEN
         elem%dipole(:) = m_send%task_real((counter + 1):(counter + NINT(m_send%task_real(counter))))
         counter = counter + 1 + NINT(m_send%task_real(counter))
      END IF

      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)
   END SUBROUTINE read_energy_result_message

! **************************************************************************************************
!> \brief create message for sending back the approximate energy of new conf
!> \param elem tree element with calculated approx energy
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE create_approx_energy_result_message(elem, m_send, &
                                                  tmc_params)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, msg_size_real

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(tmc_params))

      counter = 0

      !then float array with energy of exact potential
      msg_size_real = 1 + 1 + 1
      IF (tmc_params%pressure .GE. 0.0_dp) msg_size_real = msg_size_real + 1 + SIZE(elem%box_scale(:))

      ALLOCATE (m_send%task_real(msg_size_real))
      m_send%task_real(1) = 1
      m_send%task_real(2) = elem%e_pot_approx
      counter = 3
      ! the box size for NpT
      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         m_send%task_real(counter) = SIZE(elem%box_scale)
         m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter))) = elem%box_scale(:)
         counter = counter + 1 + INT(m_send%task_real(counter))
      END IF
      m_send%task_real(counter) = REAL(message_end_flag, KIND=dp) !message end

      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)
   END SUBROUTINE create_approx_energy_result_message

! **************************************************************************************************
!> \brief reading message for sending back the exact energy of new conf
!> \param elem tree element for storing new energy
!> \param m_send the message structure
!> \param tmc_params the param struct with necessary parameters
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_approx_energy_result(elem, m_send, tmc_params)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter

      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(m_send%info(2) .EQ. 0 .AND. m_send%info(3) .GT. 0)
      CPASSERT(ASSOCIATED(tmc_params))

      !then float array with energy of exact potential
      elem%e_pot_approx = m_send%task_real(2)
      counter = 3
      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         elem%box_scale(:) = m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter)))
         counter = counter + 1 + INT(m_send%task_real(counter))
      END IF

      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)
   END SUBROUTINE read_approx_energy_result

   !============================================================================
   ! Nested Monte Carlo request messages
   !============================================================================
! **************************************************************************************************
!> \brief creating message for Nested Monte Carlo sampling of new configuration
!> \param msg_type the status tag
!> \param elem tree element  with calculated energy
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE create_NMC_request_massage(msg_type, elem, m_send, &
                                         tmc_params)
      INTEGER                                            :: msg_type
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, msg_size_int, msg_size_real

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(ASSOCIATED(elem))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(ASSOCIATED(tmc_params))

      counter = 0
      !first integer array with element status,mol_info, move type, sub tree, element nr, temp index
      msg_size_int = 1 + SIZE(elem%elem_stat) + 1 + SIZE(elem%mol) + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1

      ALLOCATE (m_send%task_int(msg_size_int))
      ! element status
      m_send%task_int(1) = SIZE(elem%elem_stat)
      counter = 2 + m_send%task_int(1)
      m_send%task_int(2:counter - 1) = elem%elem_stat
      m_send%task_int(counter) = SIZE(elem%mol)
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = elem%mol(:)
      counter = counter + 1 + m_send%task_int(counter)
      ! element move type
      m_send%task_int(counter) = 1
      m_send%task_int(counter + 1) = elem%move_type
      counter = counter + 2
      m_send%task_int(counter) = 1
      m_send%task_int(counter + 1) = elem%nr
      counter = counter + 2
      m_send%task_int(counter) = 1
      m_send%task_int(counter + 1) = elem%sub_tree_nr
      counter = counter + 2
      m_send%task_int(counter) = 1
      m_send%task_int(counter + 1) = elem%temp_created
      m_send%task_int(counter + 2) = message_end_flag !message end

      counter = 0
      !then float array with pos, (vel), random number seed, subbox_center
      msg_size_real = 1 + SIZE(elem%pos) + 1 + SIZE(elem%rng_seed) + 1 + SIZE(elem%subbox_center(:)) + 1
      IF (msg_type .EQ. TMC_STAT_MD_REQUEST .OR. msg_type .EQ. TMC_STAT_MD_BROADCAST) &
         msg_size_real = msg_size_real + 1 + SIZE(elem%vel) ! the velocities
      IF (tmc_params%pressure .GE. 0.0_dp) msg_size_real = msg_size_real + 1 + SIZE(elem%box_scale(:)) ! box size for NpT

      ALLOCATE (m_send%task_real(msg_size_real))
      m_send%task_real(1) = SIZE(elem%pos)
      counter = 2 + INT(m_send%task_real(1))
      m_send%task_real(2:counter - 1) = elem%pos
      IF (msg_type .EQ. TMC_STAT_MD_REQUEST .OR. msg_type .EQ. TMC_STAT_MD_BROADCAST) THEN
         m_send%task_real(counter) = SIZE(elem%vel)
         m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter))) = elem%vel
         counter = counter + 1 + NINT(m_send%task_real(counter))
      END IF
      ! rng seed
      m_send%task_real(counter) = SIZE(elem%rng_seed)
      m_send%task_real(counter + 1:counter + SIZE(elem%rng_seed)) = RESHAPE(elem%rng_seed(:, :, :), (/SIZE(elem%rng_seed)/))
      counter = counter + NINT(m_send%task_real(counter)) + 1
      ! sub box center
      m_send%task_real(counter) = SIZE(elem%subbox_center(:))
      m_send%task_real(counter + 1:counter + SIZE(elem%subbox_center)) = elem%subbox_center(:)
      counter = counter + 1 + NINT(m_send%task_real(counter))
      ! the box size for NpT
      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         m_send%task_real(counter) = SIZE(elem%box_scale)
         m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter))) = elem%box_scale(:)
         counter = counter + 1 + INT(m_send%task_real(counter))
      END IF
      m_send%task_real(counter) = message_end_flag !message end

      CPASSERT(SIZE(m_send%task_int) .EQ. msg_size_int)
      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(m_send%task_int(msg_size_int) .EQ. message_end_flag)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)
   END SUBROUTINE create_NMC_request_massage

! **************************************************************************************************
!> \brief reading message for Nested Monte Carlo sampling of new configuration
!> \param msg_type the status tag
!> \param elem tree element with new coordinates
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_NMC_request_massage(msg_type, elem, m_send, &
                                       tmc_params)
      INTEGER                                            :: msg_type
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, num_dim, rnd_seed_size

      CPASSERT(.NOT. ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(m_send%info(2) .GT. 5 .AND. m_send%info(3) .GT. 8)
      CPASSERT(ASSOCIATED(tmc_params))

      counter = 0
      !first integer array with number of dimensions and random seed size
      rnd_seed_size = m_send%task_int(1 + m_send%task_int(1) + 1)

      IF (.NOT. ASSOCIATED(elem)) THEN
         CALL allocate_new_sub_tree_node(next_el=elem, nr_dim=NINT(m_send%task_real(1)), &
                                         tmc_params=tmc_params)
      END IF
      ! element status
      counter = 2 + m_send%task_int(1)
      elem%elem_stat = m_send%task_int(2:counter - 1)
      elem%mol(:) = m_send%task_int(counter + 1:counter + m_send%task_int(counter))
      counter = counter + 1 + m_send%task_int(counter)
      ! element move type
      elem%move_type = m_send%task_int(counter + 1)
      counter = counter + 2
      elem%nr = m_send%task_int(counter + 1)
      counter = counter + 2
      elem%sub_tree_nr = m_send%task_int(counter + 1)
      counter = counter + 2
      elem%temp_created = m_send%task_int(counter + 1)
      counter = counter + 2
      CPASSERT(counter .EQ. m_send%info(2))

      counter = 0
      !then float array with pos, (vel), subbox_center and temp
      num_dim = NINT(m_send%task_real(1))
      counter = 2 + INT(m_send%task_real(1))
      elem%pos = m_send%task_real(2:counter - 1)
      IF (msg_type .EQ. TMC_STAT_MD_REQUEST .OR. msg_type .EQ. TMC_STAT_MD_BROADCAST) THEN
         elem%vel = m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter)))
         counter = counter + NINT(m_send%task_real(counter)) + 1
      END IF
      ! rng seed
      elem%rng_seed(:, :, :) = RESHAPE(m_send%task_real(counter + 1:counter + SIZE(elem%rng_seed)), (/3, 2, 3/))
      counter = counter + NINT(m_send%task_real(counter)) + 1
      ! sub box center
      elem%subbox_center(:) = m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter)))
      counter = counter + 1 + NINT(m_send%task_real(counter))

      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         elem%box_scale(:) = m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter)))
         counter = counter + 1 + INT(m_send%task_real(counter))
      ELSE
         elem%box_scale(:) = 1.0_dp
      END IF

      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(m_send%task_int(m_send%info(2)) .EQ. message_end_flag)
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)
   END SUBROUTINE read_NMC_request_massage

   !============================================================================
   ! Nested Monte Carlo RESULT messages
   !============================================================================
! **************************************************************************************************
!> \brief creating message for Nested Monte Carlo sampling result
!> \param msg_type the status tag
!> \param elem tree element  with calculated energy
!> \param m_send the message structure
!> \param tmc_params environment with move types and sizes
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE create_NMC_result_massage(msg_type, elem, m_send, tmc_params)
      INTEGER                                            :: msg_type
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, msg_size_int, msg_size_real

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(tmc_params))

      !first integer array with status, nmc_acc_counts, subbox_acc_count and (subbox rejectance)
      msg_size_int = 1 + SIZE(elem%mol) &
                     + 1 + SIZE(tmc_params%nmc_move_types%mv_count) &
                     + 1 + SIZE(tmc_params%nmc_move_types%acc_count) + 1
      IF (DEBUG .GT. 0) msg_size_int = msg_size_int + 1 + 1 + 1 + 1
      IF (.NOT. ANY(tmc_params%sub_box_size .LE. 0.1_dp)) &
         msg_size_int = msg_size_int + 1 + SIZE(tmc_params%nmc_move_types%subbox_count) &
                        + 1 + SIZE(tmc_params%nmc_move_types%subbox_acc_count)

      ALLOCATE (m_send%task_int(msg_size_int))
      counter = 1
      IF (DEBUG .GT. 0) THEN
         ! send the element number back
         m_send%task_int(counter) = 1
         m_send%task_int(counter + 1) = elem%sub_tree_nr
         counter = counter + 1 + m_send%task_int(counter)
         m_send%task_int(counter) = 1
         m_send%task_int(counter + 1) = elem%nr
         counter = counter + 1 + m_send%task_int(counter)
      END IF
      ! the molecule information
      m_send%task_int(counter) = SIZE(elem%mol)
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = elem%mol(:)
      counter = counter + 1 + m_send%task_int(counter)
      ! the counters for each move type
      m_send%task_int(counter) = SIZE(tmc_params%nmc_move_types%mv_count)
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = &
         RESHAPE(tmc_params%nmc_move_types%mv_count(:, :), &
                 (/SIZE(tmc_params%nmc_move_types%mv_count)/))
      counter = counter + 1 + m_send%task_int(counter)
      ! the counter for the accepted moves
      m_send%task_int(counter) = SIZE(tmc_params%nmc_move_types%acc_count)
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = &
         RESHAPE(tmc_params%nmc_move_types%acc_count(:, :), &
                 (/SIZE(tmc_params%nmc_move_types%acc_count)/))
      counter = counter + 1 + m_send%task_int(counter)
      ! amount of rejected subbox moves
      IF (.NOT. ANY(tmc_params%sub_box_size .LE. 0.1_dp)) THEN
         m_send%task_int(counter) = SIZE(tmc_params%nmc_move_types%subbox_count)
         m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = &
            RESHAPE(tmc_params%nmc_move_types%subbox_count(:, :), &
                    (/SIZE(tmc_params%nmc_move_types%subbox_count)/))
         counter = counter + 1 + m_send%task_int(counter)
         m_send%task_int(counter) = SIZE(tmc_params%nmc_move_types%subbox_acc_count)
         m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = &
            RESHAPE(tmc_params%nmc_move_types%subbox_acc_count(:, :), &
                    (/SIZE(tmc_params%nmc_move_types%subbox_acc_count)/))
         counter = counter + 1 + m_send%task_int(counter)
      END IF
      m_send%task_int(counter) = message_end_flag ! message end

      counter = 0
      !then float array with pos,(vel, e_kin_befor_md, ekin),(forces),rng_seed,
      !                       potential,e_pot_approx,acc_prob,subbox_prob
      msg_size_real = 1 + SIZE(elem%pos) & ! pos
                      + 1 + SIZE(elem%rng_seed) & ! rng_seed
                      + 1 + 1 & ! potential
                      + 1 + 1 & ! e_pot_approx
                      + 1 ! check bit

      IF (msg_type .EQ. TMC_STAT_MD_REQUEST .OR. msg_type .EQ. TMC_STAT_MD_RESULT .OR. &
          msg_type .EQ. TMC_STAT_MD_BROADCAST) &
         msg_size_real = msg_size_real + 1 + SIZE(elem%vel) + 1 + 1 + 1 + 1 ! for MD also: vel, e_kin_befor_md, ekin

      ALLOCATE (m_send%task_real(msg_size_real))
      ! pos
      counter = 1
      m_send%task_real(counter) = SIZE(elem%pos)
      m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter))) = elem%pos
      counter = counter + 1 + NINT(m_send%task_real(counter))
      ! rng seed
      m_send%task_real(counter) = SIZE(elem%rng_seed)
      m_send%task_real(counter + 1:counter + SIZE(elem%rng_seed)) = &
         RESHAPE(elem%rng_seed(:, :, :), (/SIZE(elem%rng_seed)/))
      counter = counter + 1 + NINT(m_send%task_real(counter))
      ! potential
      m_send%task_real(counter) = 1
      m_send%task_real(counter + 1) = elem%potential
      counter = counter + 2
      ! approximate potential energy
      m_send%task_real(counter) = 1
      m_send%task_real(counter + 1) = elem%e_pot_approx
      counter = counter + 2
      ! for MD also: vel, e_kin_befor_md, ekin
      IF (msg_type .EQ. TMC_STAT_MD_REQUEST .OR. msg_type .EQ. TMC_STAT_MD_RESULT .OR. &
          msg_type .EQ. TMC_STAT_MD_BROADCAST) THEN
         m_send%task_real(counter) = SIZE(elem%vel)
         m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter))) = elem%vel
         counter = counter + 1 + INT(m_send%task_real(counter))
         m_send%task_real(counter) = 1
         m_send%task_real(counter + 1) = elem%ekin_before_md
         counter = counter + 2
         m_send%task_real(counter) = 1
         m_send%task_real(counter + 1) = elem%ekin
         counter = counter + 2
      END IF
      m_send%task_real(counter) = message_end_flag ! message end

      CPASSERT(SIZE(m_send%task_int) .EQ. msg_size_int)
      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(m_send%task_int(msg_size_int) .EQ. message_end_flag)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)
   END SUBROUTINE create_NMC_result_massage

! **************************************************************************************************
!> \brief reading message for Nested Monte Carlo sampling result
!> \param msg_type the status tag
!> \param elem tree element  with calculated energy
!> \param m_send the message structure
!> \param tmc_params environment with move types and sizes
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_NMC_result_massage(msg_type, elem, m_send, tmc_params)
      INTEGER                                            :: msg_type
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter
      INTEGER, DIMENSION(:, :), POINTER                  :: acc_counter, mv_counter, &
                                                            subbox_acc_counter, subbox_counter

      NULLIFY (mv_counter, subbox_counter, acc_counter, subbox_acc_counter)

      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(m_send%info(2) .GT. 0 .AND. m_send%info(3) .GT. 0)
      CPASSERT(ASSOCIATED(tmc_params))

      !first integer array with element status, random number seed, and move type
      counter = 1
      IF (DEBUG .GT. 0) THEN
         IF ((m_send%task_int(counter + 1) .NE. elem%sub_tree_nr) .AND. (m_send%task_int(counter + 3) .NE. elem%nr)) THEN
            CPABORT("read_NMC_result_massage: got result of wrong element")
         END IF
         counter = counter + 2 + 2
      END IF
      ! the molecule information
      elem%mol(:) = m_send%task_int(counter + 1:counter + m_send%task_int(counter))
      counter = counter + 1 + m_send%task_int(counter)
      ! the counters for each move type
      ALLOCATE (mv_counter(0:SIZE(tmc_params%nmc_move_types%mv_count(:, 1)) - 1, &
                           SIZE(tmc_params%nmc_move_types%mv_count(1, :))))
      mv_counter(:, :) = RESHAPE(m_send%task_int(counter + 1:counter + m_send%task_int(counter)), &
                                 (/SIZE(tmc_params%nmc_move_types%mv_count(:, 1)), &
                                   SIZE(tmc_params%nmc_move_types%mv_count(1, :))/))
      counter = counter + 1 + m_send%task_int(counter)
      ! the counter for the accepted moves
      ALLOCATE (acc_counter(0:SIZE(tmc_params%nmc_move_types%acc_count(:, 1)) - 1, &
                            SIZE(tmc_params%nmc_move_types%acc_count(1, :))))
      acc_counter(:, :) = RESHAPE(m_send%task_int(counter + 1:counter + m_send%task_int(counter)), &
                                  (/SIZE(tmc_params%nmc_move_types%acc_count(:, 1)), &
                                    SIZE(tmc_params%nmc_move_types%acc_count(1, :))/))
      counter = counter + 1 + m_send%task_int(counter)
      ! amount of rejected subbox moves
      IF (.NOT. ANY(tmc_params%sub_box_size .LE. 0.1_dp)) THEN
         ALLOCATE (subbox_counter(SIZE(tmc_params%nmc_move_types%subbox_count(:, 1)), &
                                  SIZE(tmc_params%nmc_move_types%subbox_count(1, :))))
         subbox_counter(:, :) = RESHAPE(m_send%task_int(counter + 1:counter + m_send%task_int(counter)), &
                                        (/SIZE(tmc_params%nmc_move_types%subbox_count(:, 1)), &
                                          SIZE(tmc_params%nmc_move_types%subbox_count(1, :))/))
         counter = counter + 1 + m_send%task_int(counter)
         ALLOCATE (subbox_acc_counter(SIZE(tmc_params%nmc_move_types%subbox_acc_count(:, 1)), &
                                      SIZE(tmc_params%nmc_move_types%subbox_acc_count(1, :))))
         subbox_acc_counter(:, :) = RESHAPE(m_send%task_int(counter + 1:counter + m_send%task_int(counter)), &
                                            (/SIZE(tmc_params%nmc_move_types%subbox_acc_count(:, 1)), &
                                              SIZE(tmc_params%nmc_move_types%subbox_acc_count(1, :))/))
         counter = counter + 1 + m_send%task_int(counter)
      END IF
      CPASSERT(counter .EQ. m_send%info(2))

      counter = 0
      !then float array with pos, (vel, e_kin_befor_md, ekin), (forces), rng_seed, potential, e_pot_approx
      counter = 1
      ! pos
      elem%pos = m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter)))
      counter = counter + 1 + NINT(m_send%task_real(counter))
      ! rng seed
      elem%rng_seed(:, :, :) = RESHAPE(m_send%task_real(counter + 1:counter + SIZE(elem%rng_seed)), (/3, 2, 3/))
      counter = counter + 1 + NINT(m_send%task_real(counter))
      ! potential
      elem%potential = m_send%task_real(counter + 1)
      counter = counter + 2
      ! approximate potential energy
      elem%e_pot_approx = m_send%task_real(counter + 1)
      counter = counter + 2
      ! for MD also: vel, e_kin_befor_md, ekin
      IF (msg_type .EQ. TMC_STAT_MD_REQUEST .OR. msg_type .EQ. TMC_STAT_MD_RESULT .OR. &
          msg_type .EQ. TMC_STAT_MD_BROADCAST) THEN
         elem%vel = m_send%task_real(counter + 1:counter + NINT(m_send%task_real(counter)))
         counter = counter + 1 + INT(m_send%task_real(counter))
         IF (.NOT. (tmc_params%task_type .EQ. task_type_gaussian_adaptation)) &
            elem%ekin_before_md = m_send%task_real(counter + 1)
         counter = counter + 2
         elem%ekin = m_send%task_real(counter + 1)
         counter = counter + 2
      END IF

      CALL add_mv_prob(move_types=tmc_params%nmc_move_types, prob_opt=tmc_params%esimate_acc_prob, &
                       mv_counter=mv_counter, acc_counter=acc_counter)
      IF (.NOT. ANY(tmc_params%sub_box_size .LE. 0.1_dp)) THEN
         CALL add_mv_prob(move_types=tmc_params%nmc_move_types, prob_opt=tmc_params%esimate_acc_prob, &
                          subbox_counter=subbox_counter, subbox_acc_counter=subbox_acc_counter)
      END IF

      DEALLOCATE (mv_counter, acc_counter)
      IF (.NOT. ANY(tmc_params%sub_box_size .LE. 0.1_dp)) &
         DEALLOCATE (subbox_counter, subbox_acc_counter)
      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(m_send%task_int(m_send%info(2)) .EQ. message_end_flag)
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)
   END SUBROUTINE read_NMC_result_massage

   !============================================================================
   ! Analysis element messages
   !============================================================================
! **************************************************************************************************
!> \brief creating message for requesting analysing a new configuration
!>        we plot temperatur index into the sub tree number and
!>        the Markov chain number into the element number
!> \param list_elem ...
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE create_analysis_request_message(list_elem, m_send, &
                                              tmc_params)
      TYPE(elem_list_type), POINTER                      :: list_elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter, msg_size_int, msg_size_real

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(.NOT. ALLOCATED(m_send%task_int))
      CPASSERT(.NOT. ALLOCATED(m_send%task_real))
      CPASSERT(ASSOCIATED(list_elem))
      CPASSERT(ASSOCIATED(tmc_params))

      counter = 0
      !first integer array
      msg_size_int = 1 + 1 + 1 + 1 + 1 ! 1+SIZE(list_elem%elem%sub_tree_nr) +1+SIZE(list_elem%elem%nr)
      ALLOCATE (m_send%task_int(msg_size_int))
      counter = 1
      m_send%task_int(counter) = 1 ! temperature index
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = list_elem%temp_ind
      counter = counter + 1 + m_send%task_int(counter)
      m_send%task_int(counter) = 1 ! Markov chain number
      m_send%task_int(counter + 1:counter + m_send%task_int(counter)) = list_elem%nr
      counter = counter + 1 + m_send%task_int(counter)
      m_send%task_int(counter) = message_end_flag
      CPASSERT(SIZE(m_send%task_int) .EQ. msg_size_int)
      CPASSERT(m_send%task_int(msg_size_int) .EQ. message_end_flag)

      !then float array with pos
      msg_size_real = 1 + SIZE(list_elem%elem%pos) + 1
      IF (tmc_params%pressure .GE. 0.0_dp) msg_size_real = msg_size_real + 1 + SIZE(list_elem%elem%box_scale(:))
      ALLOCATE (m_send%task_real(msg_size_real))
      m_send%task_real(1) = SIZE(list_elem%elem%pos)
      counter = 2 + INT(m_send%task_real(1))
      m_send%task_real(2:counter - 1) = list_elem%elem%pos
      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         m_send%task_real(counter) = SIZE(list_elem%elem%box_scale)
         m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter))) = list_elem%elem%box_scale(:)
         counter = counter + 1 + INT(m_send%task_real(counter))
      END IF
      m_send%task_real(counter) = REAL(message_end_flag, KIND=dp) !message end

      CPASSERT(SIZE(m_send%task_real) .EQ. msg_size_real)
      CPASSERT(INT(m_send%task_real(msg_size_real)) .EQ. message_end_flag)
   END SUBROUTINE create_analysis_request_message

! **************************************************************************************************
!> \brief reading message for requesting exact energy of new configuration
!> \param elem tree element with new coordinates
!> \param m_send the message structure
!> \param tmc_params stuct with parameters (global settings)
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_analysis_request_message(elem, m_send, tmc_params)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: counter

      CPASSERT(ASSOCIATED(m_send))
      CPASSERT(m_send%info(3) .GT. 0)
      CPASSERT(ASSOCIATED(tmc_params))
      CPASSERT(.NOT. ASSOCIATED(elem))

      ! initialize the new sub tree element
      IF (.NOT. ASSOCIATED(elem)) THEN
         CALL allocate_new_sub_tree_node(next_el=elem, nr_dim=NINT(m_send%task_real(1)), &
                                         tmc_params=tmc_params)
      END IF
      ! read the integer values
      CPASSERT(m_send%info(2) .GT. 0)
      counter = 1
      elem%sub_tree_nr = m_send%task_int(counter + 1)
      counter = counter + 1 + m_send%task_int(counter)
      elem%nr = m_send%task_int(counter + 1)
      counter = counter + 1 + m_send%task_int(counter)
      CPASSERT(m_send%task_int(counter) .EQ. message_end_flag)

      !float array with pos
      counter = 0
      counter = 1 + NINT(m_send%task_real(1))
      elem%pos = m_send%task_real(2:counter)
      counter = counter + 1
      IF (tmc_params%pressure .GE. 0.0_dp) THEN
         elem%box_scale(:) = m_send%task_real(counter + 1:counter + INT(m_send%task_real(counter)))
         counter = counter + 1 + INT(m_send%task_real(counter))
      END IF

      CPASSERT(counter .EQ. m_send%info(3))
      CPASSERT(INT(m_send%task_real(m_send%info(3))) .EQ. message_end_flag)
   END SUBROUTINE read_analysis_request_message

   !============================================================================
   ! SCF step energies (receiving from CP2K)
   !============================================================================
! **************************************************************************************************
!> \brief routine cancel the other group participants
!> \param elem tree element  with approximated energy
!> \param m_send the message structure
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE read_scf_step_ener(elem, m_send)
      TYPE(tree_type), POINTER                           :: elem
      TYPE(message_send), POINTER                        :: m_send

      CPASSERT(ASSOCIATED(elem))
      CPASSERT(ASSOCIATED(m_send))

      elem%scf_energies(MOD(elem%scf_energies_count, 4) + 1) = m_send%task_real(1)
      elem%scf_energies_count = elem%scf_energies_count + 1

   END SUBROUTINE read_scf_step_ener

! **************************************************************************************************
!> \brief routines send atom names to the global master
!>        (using broadcast in a specialized group consisting of the master
!>        and the first energy worker master)
!> \param atoms ...
!> \param source ...
!> \param para_env the communicator environment
!> \author Mandes 12.2012
! **************************************************************************************************
   SUBROUTINE communicate_atom_types(atoms, source, para_env)
      TYPE(tmc_atom_type), DIMENSION(:), POINTER         :: atoms
      INTEGER                                            :: source
      TYPE(mp_para_env_type), POINTER                    :: para_env

      CHARACTER(LEN=default_string_length), &
         ALLOCATABLE, DIMENSION(:)                       :: msg(:)
      INTEGER                                            :: i

      CPASSERT(ASSOCIATED(para_env))
      CPASSERT(source .GE. 0)
      CPASSERT(source .LT. para_env%num_pe)

      ALLOCATE (msg(SIZE(atoms)))
      IF (para_env%mepos .EQ. source) THEN
         DO i = 1, SIZE(atoms)
            msg(i) = atoms(i)%name
         END DO
         CALL para_env%bcast(msg, source)
      ELSE
         CALL para_env%bcast(msg, source)
         DO i = 1, SIZE(atoms)
            atoms(i)%name = msg(i)
         END DO
      END IF
      DEALLOCATE (msg)
   END SUBROUTINE communicate_atom_types

! **************************************************************************************************
!> \brief send stop command to all group participants
!> \param para_env ...
!> \param worker_info ...
!> \param tmc_params ...
!> \param
!> \param
!> \author Mandes 01.2013
! **************************************************************************************************
   SUBROUTINE stop_whole_group(para_env, worker_info, tmc_params)
      TYPE(mp_para_env_type), POINTER                    :: para_env
      TYPE(elem_array_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: worker_info
      TYPE(tmc_param_type), POINTER                      :: tmc_params

      INTEGER                                            :: act_rank, dest_rank, stat
      LOGICAL                                            :: flag
      LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: rank_stoped

!    INTEGER, DIMENSION(MPI_STATUS_SIZE)      :: status_single

      CPASSERT(ASSOCIATED(para_env))
      CPASSERT(ASSOCIATED(tmc_params))

      ALLOCATE (rank_stoped(0:para_env%num_pe - 1))
      rank_stoped(:) = .FALSE.
      rank_stoped(para_env%mepos) = .TRUE.

      ! global master
      IF (PRESENT(worker_info)) THEN
         CPASSERT(ASSOCIATED(worker_info))
         ! canceling running jobs and stop workers
         worker_group_loop: DO dest_rank = 1, para_env%num_pe - 1
            ! busy workers have to be canceled
            IF (worker_info(dest_rank)%busy) THEN
               stat = TMC_CANCELING_MESSAGE
               act_rank = dest_rank
               CALL tmc_message(msg_type=stat, send_recv=send_msg, dest=act_rank, &
                                para_env=para_env, tmc_params=tmc_params)
            ELSE
               ! send stop message
               stat = TMC_STATUS_FAILED
               act_rank = dest_rank
               CALL tmc_message(msg_type=stat, send_recv=send_msg, dest=act_rank, &
                                para_env=para_env, tmc_params=tmc_params)
            END IF
         END DO worker_group_loop
      ELSE
         ! group master send stop message to all participants
         stat = TMC_STATUS_FAILED
         CALL tmc_message(msg_type=stat, send_recv=send_msg, dest=bcast_group, &
                          para_env=para_env, tmc_params=tmc_params)
      END IF

      ! receive stop message receipt
      IF (para_env%mepos .EQ. MASTER_COMM_ID) THEN
         wait_for_receipts: DO
            ! check incomming messages
            stat = TMC_STATUS_WAIT_FOR_NEW_TASK
            dest_rank = 999
            IF (PRESENT(worker_info)) THEN
               ! mast have to be able to receive results, if canceling was too late
               CALL tmc_message(msg_type=stat, send_recv=recv_msg, dest=dest_rank, &
                                para_env=para_env, tmc_params=tmc_params, &
                                elem_array=worker_info(:), success=flag)
            ELSE
               CALL tmc_message(msg_type=stat, send_recv=recv_msg, dest=dest_rank, &
                                para_env=para_env, tmc_params=tmc_params)
            END IF
            SELECT CASE (stat)
            CASE (TMC_STATUS_WAIT_FOR_NEW_TASK)
               ! no message received
            CASE (TMC_CANCELING_RECEIPT)
               IF (PRESENT(worker_info)) THEN
                  worker_info(dest_rank)%busy = .FALSE.
                  stat = TMC_STATUS_FAILED
                  ! send stop message
                  CALL tmc_message(msg_type=stat, send_recv=send_msg, dest=dest_rank, &
                                   para_env=para_env, tmc_params=tmc_params)
               ELSE
                  CPABORT("group master should not receive cancel receipt")
               END IF
            CASE (TMC_STATUS_STOP_RECEIPT)
               rank_stoped(dest_rank) = .TRUE.
            CASE (TMC_STAT_ENERGY_RESULT, TMC_STAT_NMC_RESULT, TMC_STAT_MD_RESULT, &
                  TMC_STAT_SCF_STEP_ENER_RECEIVE, TMC_STAT_APPROX_ENERGY_RESULT, TMC_STAT_ANALYSIS_RESULT)
               ! nothing to do, canceling message already sent
            CASE DEFAULT
               CALL cp_abort(__LOCATION__, &
                             "master received status "//cp_to_string(stat)// &
                             " while stopping workers")
            END SELECT
            IF (ALL(rank_stoped)) EXIT wait_for_receipts
         END DO wait_for_receipts
      ELSE
         CPABORT("only (group) master should stop other participants")
      END IF
   END SUBROUTINE stop_whole_group

END MODULE tmc_messages
